/*
 * Project Name: qcpj-trunk
 * File Name: SecurityContext.java
 * Class Name: SecurityContext
 *
 * Copyright 2014 Hengtian Software Inc
 *
 * Licensed under the Hengtiansoft
 *
 * http://www.hengtiansoft.com
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.common.security;

import com.common.CustomRealm;
import com.common.constant.ApplicationConstant;
import com.common.util.AppConfigUtil;
import com.common.util.StringUtil;
import com.common.util.WebUtil;
import com.hzyzt.user.dto.UserDto;
import com.hzyzt.user.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.CachingSecurityManager;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpSession;
import java.util.*;


/**
 * Class Name: SecurityContext Description: TODO.
 * 
 * @author SC
 * 
 */
public class BaseSecurityContext {

	private static final String UNCHECKED = "unchecked";
	
	private static final String USERISLOGIN = "userIsLogin";
	
	private static final String USERSESSIONS = "userSessions";
	
	private static final Logger LOGGER = LoggerFactory
			.getLogger(BaseSecurityContext.class);

	private static final String CACHE_NAME_AUTHZ = "cache.name.authz";

	private static final String CACHE_NAME_AUTHC = "cache.name.authc";
	
	public static final String CAPTCHA_NOT = "captcha.not";
	public static final String CAPTCHA_ERROR = "captcha.error";
	public static final String CAPTCHA_SUCCESS = "captcha.success";

	private static Map<String,String> captchaMap = new HashMap<String,String>();

	@Autowired
	private static UserService userService;
	
	private static final int NUMBER300 = 300;
	
	
	public static String isCaptchaLogin(String username){
	    if(StringUtil.isStrNullOrEmpty(username)){
	        return CAPTCHA_NOT;
	    }
	    return captchaMap.get(username);
	}
	
	/**
	 * Description: 获取当前用户的基本信息。.
	 * 
	 * @return SysuserDto 系统.
	 */
	public UserDto getCurrentUser() {
		Subject subject = getSubject();
		if (subject == null) {
			return null;
		}
		return (UserDto) subject.getSession().getAttribute(ApplicationConstant.SESSIONUSER);
	}

	/**
	 * Description: 是否已登录.
	 * 
	 * @return isAuthenticated 登陆.
	 */
	public static boolean isAuthenticated() {
		Subject subject = getSubject();
		if (subject == null) {
			return false;
		}
		return getSubject().isAuthenticated();
	}

	/**
	 * Description: 是否已记住.
	 * 
	 * @return Remember 记住.
	 */
	public static boolean isRemembered() {
		Subject subject = getSubject();
		if (subject == null) {
			return false;
		}
		return getSubject().isRemembered();
	}
	

	@SuppressWarnings(UNCHECKED)
	public static Session login(String userName, String password,
			Boolean rememberMe, HttpSession httpSession,UserDto userDto
			) throws IncorrectCredentialsException,
			LockedAccountException {
		long start = System.currentTimeMillis();
		UsernamePasswordToken token = new UsernamePasswordToken(userName,
				password, rememberMe);
		Subject currentUser = SecurityUtils.getSubject();
		// This is to prevent session fixation attack, see:
		try {
			currentUser.getSession().stop();
		} catch (Exception e) {
			LOGGER.warn("session invalid");
		}
		// this will create a new session by default in applications that allow
		// session state:
		currentUser.login(token);
		Session session = currentUser.getSession();
		LOGGER.debug("User {} login successfully, session id {}", userName,
				session.getId());
		/*UserDto user = null;
		try {
			user = userService.getUserByUserName(userName);
			user = new UserDto();
		} catch (Exception e) {
			e.printStackTrace();
		}*/

		session.setAttribute(ApplicationConstant.SESSIONUSER, userDto);
		long end = System.currentTimeMillis();
		LOGGER.debug("login() completed for user {}, total time spent: {}ms",
				userName, end - start);
		// 添加登陆
		// 新创建的session均添加到HashSet集中
		return session;
	}

	/**
	 * 登出当前用户.
	 */
	public static void logout() {
		getSubject().logout();
	}

	/**
	 * Description: 清除指定用户的授权信息缓存。.
	 * 
	 * @param userName 身份.
	 */
	public static void clearAuthzCache(String userName) {
		RealmSecurityManager sm = (RealmSecurityManager) SecurityUtils
				.getSecurityManager();
		for (Realm realm : sm.getRealms()) {
			if (realm instanceof CustomRealm) {
				CustomRealm jdbcRealm = (CustomRealm) realm;
				SimplePrincipalCollection spc = new SimplePrincipalCollection(
						userName, realm.getName());
				jdbcRealm.clearCached();
			}
		}
		LOGGER.info("Authorization cache cleared for user: {}", userName);
	}

	/**
	 * Description: 清除指定用户列表的授权信息缓存。.
	 * 
	 * @param users 使用者.
	 */
	public static void clearAuthzCache(List<String> users) {
		for (String user : users) {
			clearAuthzCache(user);
		}
	}

	/**
	 * Description: 清除所有用户的授权信息缓存。.
	 * 
	 */
	public static void clearAllAuthzCache() {
		CacheManager cm = (CacheManager) ((CachingSecurityManager) SecurityUtils
				.getSecurityManager()).getCacheManager();
		cm.getCache(AppConfigUtil.getConfig(CACHE_NAME_AUTHZ)).clear();
	}

	/**
	 * Description: 清除指定用户的认证信息缓存。.
	 * 
	 * @param userName 姓名.
	 */
	public static void clearAuthcCache(String userName) {
		RealmSecurityManager sm = (RealmSecurityManager) SecurityUtils
				.getSecurityManager();
		for (Realm realm : sm.getRealms()) {
			if (realm instanceof CustomRealm) {
				CustomRealm jdbcRealm = (CustomRealm) realm;
				SimplePrincipalCollection spc = new SimplePrincipalCollection(
						userName, realm.getName());
				jdbcRealm.clearCached();
			}
		}
	}

	/**
	 * Description: 清除指定用户list的认证信息缓存。.
	 * 
	 * @param users 使用者.
	 */
	public static void clearAuthcCache(List<String> users) {
		for (String user : users) {
			clearAuthcCache(user);
		}
	}

	/**
	 * Description: 清除所有用户的认证信息缓存。.
	 * 
	 */
	public static void clearAllAuthcCache() {
		CacheManager cm = (CacheManager) ((CachingSecurityManager) SecurityUtils
				.getSecurityManager()).getCacheManager();
		cm.getCache(AppConfigUtil.getConfig(CACHE_NAME_AUTHC)).clear();
	}

	/**
	 * Description: 清除当前用户的授权信息缓存.
	 * 
	 */
	public void clearCurrentAuthzCache() {
		clearAuthzCache(getSubject().getPrincipal().toString());
	}

	/**
	 * Description: 验证当前用户是否拥有该权限。.
	 * 
	 * @param permission 许可.
	 * @return permit 允许
	 */
	public boolean hasPermission(String permission) {
		Subject subject = getSubject();
		return subject == null ? false : subject.isPermitted(permission);
	}

	/**
	 * Description: 验证当前用户是否拥有所有以下权限。.
	 * 
	 * @param permissions 许可.
	 * @return permit 允许
	 */
	public boolean hasAllPermissions(String... permissions) {
		Subject subject = getSubject();
		return subject == null ? false : subject.isPermittedAll(permissions);
	}

	/**
	 * Description: 验证当前用户是否拥有以下任意一个权限.
	 * 
	 * @param permissions 许可.
	 * @return permit 允许
	 */
	public static boolean hasAnyPermission(String[] permissions) {
		Subject subject = getSubject();
		if (subject != null && permissions != null) {
			for (int i = 0; i < permissions.length; i++) {
				String permission = permissions[i];
				if (permission != null
						&& subject.isPermitted(permission.trim())) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * 检查是否有权限，若无则抛出异常。.
	 * 
	 * @see Subject#checkPermission(String permission)
	 * @param permission 许可.
	 * @throws AuthorizationException 希望
	 */
	public void checkPermission(String permission)
			throws AuthorizationException {
		Subject subject = getSubject();
		if (subject == null) {
			throw new AuthorizationException(
					"No permission as there is no subject bound.");
		}
		subject.checkPermission(permission);
	}

	/**
	 * Description: 验证当前用户是否属于以下所有角色。请通过权限而不是角色做判断，比如hasPermission。.
	 * 
	 * @param roles 角色.
	 * @return collect 收集
	 */
	@Deprecated
	public boolean hasAllRoles(Collection<String> roles) {
		return getSubject().hasAllRoles(roles);
	}

	/**
	 * Description: 验证当前用户是否属于以下任意一个角色。请通过权限而不是角色做判断，比如hasPermission。.
	 * 
	 * @param roleNames 名字.
	 * @return collect 收集
	 */
	@Deprecated
	public boolean hasAnyRoles(Collection<String> roleNames) {
		Subject subject = getSubject();
		if (subject != null && roleNames != null) {
			for (String role : roleNames) {
				if (role != null && subject.hasRole(role)) {
					return true;
				}
			}
		}
		return false;
	}

	private static Subject getSubject() {
		try {
			return SecurityUtils.getSubject();
		} catch (Exception e) {
			LOGGER.warn(
					"Failed to get Subject, maybe user is not login or session is lost:",
					e);
			return null;
		}
	}

	/**
	 * @param username 名字.
	 * @return get 得到
	 */
	public static HashSet<HttpSession> getSessionByUsername(String username) {

		@SuppressWarnings(UNCHECKED)
		HashSet<HttpSession> sessions = (HashSet<HttpSession>) WebUtil
				.getThreadSession().getServletContext()
				.getAttribute("loginSessions");
		HashSet<HttpSession> httpSessions = new HashSet<HttpSession>();
		for (HttpSession session : sessions) {
			if (null != session
					&& StringUtil
							.isEqualObj(
									String.valueOf(session
											.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY)),
									username)) {
				httpSessions.add(session);
			}
		}
		return httpSessions;
	}

}
